package pwd.allen.web.config;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ImportResource;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import pwd.allen.redis.service.RedisService;
import pwd.allen.web.annotation.RequestLimit;
import pwd.allen.web.enums.KeyEnum;
import pwd.allen.web.enums.LimitEnum;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;


/**
 * 基于Aspect aop 实现防刷功能
 * @author pwdan
 * @create 2020-10-22 23:31
 **/
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@ImportResource("classpath*:redis.xml")
@Component
@Aspect
public class RequestLimitConfig {

    @Autowired
    private RedisService redisService;



    //<editor-fold desc="防刷AOP切面逻辑">
    @Pointcut(value = "@annotation(pwd.allen.web.annotation.RequestLimit)")
    public void requestLimitPointCut() {}
    @Around("requestLimitPointCut()")
    public Object requestLimit(ProceedingJoinPoint joinPoint) throws Throwable {
        Object rel;
        StringBuilder redisKeyStrBuilder = new StringBuilder("REQUEST_LIMIT:");

        RequestLimit requestLimit = null;
        Signature signature = joinPoint.getSignature();
        if (signature instanceof MethodSignature) {
            Method method = MethodSignature.class.cast(signature).getMethod();
            requestLimit = method.getAnnotation(RequestLimit.class);
            if (requestLimit.flagUseMethodName()) {
                redisKeyStrBuilder.append(method.getDeclaringClass().getSimpleName()).append(".").append(method.getName()).append("_");
            }
        }
        try {
            if (requestLimit.keyType() == KeyEnum.PARAM) {
                BeanWrapper beanWrapper = new BeanWrapperImpl(joinPoint);
                Object propertyValue = null;
                try {
                    propertyValue = beanWrapper.getPropertyValue(requestLimit.value());
                } catch (BeansException e) {}
                if (propertyValue != null) {
                    redisKeyStrBuilder.append(propertyValue.toString());
                }
            } else if (requestLimit.keyType() == KeyEnum.IP) {
                ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                HttpServletRequest request = servletRequestAttributes.getRequest();
                String ip = null;
            }
        } catch (Exception e) {
        }
        if (requestLimit.limitType() == LimitEnum.ASYNC && redisService.hasKey(redisKeyStrBuilder.toString())) {
            return new RuntimeException("您的请求正在处理中，请勿频繁请求！");
        }
        redisService.set(redisKeyStrBuilder.toString(), new Date(), requestLimit.seconds());

        try {
            rel = joinPoint.proceed();
        } finally {
            if (requestLimit.limitType() == LimitEnum.ASYNC) {
                //清缓存
                redisService.del(redisKeyStrBuilder.toString());
            }
        }

        return rel;
    }
    //</editor-fold>

}
